#include "../../server/mq_message.hpp"
#include <iostream>
#include <vector>
#include <gtest/gtest.h>

using namespace xzt;

MessageManager::ptr p_mm_1;
MessageManager::ptr p_mm_2;

// p_mm_1和p_mm_2分别代表两个MessageManager对象，用于测试消息共享。
// 其中p_mm_1用于插入消息，p_mm_2用于从文件读取消息。

class MessageTest: public testing::Environment
{
    virtual void SetUp() override
    {
        p_mm_1 = std::make_shared<MessageManager>("./data/message.db");
        p_mm_2 = std::make_shared<MessageManager>("./data/message.db");
        p_mm_1->initQueueMessage("test_queue");
    }

    virtual void TearDown() override
    {
        p_mm_1->clear();
    }
};

// 新增消息测试
// 经过测试发现，插入消息时BasicPropeties参数在每次插入都需要使用不用的对象，否则由于id值相同，
// 导致QueueMessage层的持久化hash中插入失败（因为key值相同），进而导致消息丢失。
TEST(MessageTest, insert_test_1)
{
    std::vector<std::shared_ptr<BasicPropeties>> props_vec(3);
    for(auto& p_props : props_vec)
    {
        p_props = std::make_shared<xzt::BasicPropeties>();
        p_props->set_id(UUIDHelper::uuid());
        p_props->set_delivery_mode(DeliveryMode::DURABLE);
        p_props->set_routing_key(".#..@fc.wb");
    }

    // 第二个参数为nullptr时，最后一个参数设定存储模式才有效
    p_mm_1->insert("test_queue", props_vec[0].get(), "Hello World-1", DeliveryMode::DURABLE);
    p_mm_1->insert("test_queue", props_vec[1].get(), "Hello World-2", DeliveryMode::UNDURABLE);
    p_mm_1->insert("test_queue", nullptr, "Hello World-3", DeliveryMode::DURABLE);
    p_mm_1->insert("test_queue", nullptr, "Hello World-4", DeliveryMode::UNDURABLE);

    ASSERT_EQ(p_mm_1->durable_count("test_queue"), 3);
    EXPECT_EQ(p_mm_1->total_count("test_queue"), 3);
    EXPECT_EQ(p_mm_1->getable_count("test_queue"), 4);
    EXPECT_EQ(p_mm_1->waitcak_count("test_queue"), 0);
}

void debug_msg_info(const MessagePtr& p_msg)
{
    DLOG("--------msg info--------");
    DLOG("msg_id: %s", p_msg->payload().propeties().id().c_str());
    DLOG("msg_body: %s", p_msg->payload().body().c_str());
    DLOG("msg_delivery_mode: %d", p_msg->payload().propeties().delivery_mode());
    DLOG("------------------------");
}

// 读取消息测试：测试分别在获取消息但未确认时，查看待推送和待确认消息数量是否正确
// TEST(MessageTest, select_test_1)
// {
//     p_mm_2->initQueueMessage("test_queue");
//     ASSERT_NE(p_mm_2, nullptr);
//     // 测试从文件中恢复消息
//     EXPECT_EQ(p_mm_2->getable_count("test_queue"), 3);

//     // 下面 old_getable_count = getable_count + waitcak_count
//     MessagePtr p_msg1 = p_mm_2->front("test_queue");
//     ASSERT_NE(p_msg1, nullptr);
//     EXPECT_EQ(p_msg1->payload().body(), std::string("Hello World-1"));
//     EXPECT_EQ(p_mm_2->getable_count("test_queue"), 2);
//     EXPECT_EQ(p_mm_2->waitcak_count("test_queue"), 1);
//     debug_msg_info(p_msg1);

//     MessagePtr p_msg2 = p_mm_2->front("test_queue");
//     EXPECT_EQ(p_msg2->payload().body(), std::string("Hello World-2"));
//     EXPECT_EQ(p_mm_2->getable_count("test_queue"), 1);
//     EXPECT_EQ(p_mm_2->waitcak_count("test_queue"), 2);
//     debug_msg_info(p_msg2);

//     MessagePtr p_msg3 = p_mm_2->front("test_queue");
//     EXPECT_EQ(p_msg3->payload().body(), std::string("Hello World-3"));
//     EXPECT_EQ(p_mm_2->getable_count("test_queue"), 0);
//     EXPECT_EQ(p_mm_2->waitcak_count("test_queue"), 3);
//     debug_msg_info(p_msg3);

//     // msg4对应存储模式为UNDURABLE，在recovery时不会被读取
//     MessagePtr p_msg4 = p_mm_2->front("test_queue");
//     debug_msg_info(p_msg4);
//     ASSERT_EQ(p_msg4, nullptr);
// }

// TEST(MessageTest, insert_test_2)
// {
//     p_mm_1->insert("test_queue", nullptr, "Hello World-1", DeliveryMode::DURABLE);
//     p_mm_1->insert("test_queue", nullptr, "Hello World-2", DeliveryMode::DURABLE);
//     p_mm_1->insert("test_queue", nullptr, "Hello World-3", DeliveryMode::DURABLE);
//     p_mm_1->insert("test_queue", nullptr, "Hello World-4", DeliveryMode::DURABLE);

//     ASSERT_EQ(p_mm_1->durable_count("test_queue"), 4);
//     EXPECT_EQ(p_mm_1->total_count("test_queue"), 4);
//     EXPECT_EQ(p_mm_1->getable_count("test_queue"), 4);
//     EXPECT_EQ(p_mm_1->waitcak_count("test_queue"), 0);
// }


// 确认（或删除）消息测试：测试确认消息后，查看持久化和待确认消息数量是否正确
TEST(MessageTest, delete_test)
{
    p_mm_2->initQueueMessage("test_queue");
    DLOG("##############读取文件后初始状态##############");
    DLOG("test_queue getable_count: %ld", p_mm_2->getable_count("test_queue"));
    DLOG("test_queue waitcak_count: %ld", p_mm_2->waitcak_count("test_queue"));
    DLOG("test_queue total_count: %ld", p_mm_2->total_count("test_queue"));
    DLOG("test_queue durable_count: %ld", p_mm_2->durable_count("test_queue"));
    DLOG("############################################");

    MessagePtr p_msg1 = p_mm_2->front("test_queue");
    ASSERT_NE(p_msg1, nullptr);
    EXPECT_EQ(p_msg1->payload().body(), std::string("Hello World-1"));
    EXPECT_EQ(p_mm_2->getable_count("test_queue"), 2);
    EXPECT_EQ(p_mm_2->waitcak_count("test_queue"), 1);
    debug_msg_info(p_msg1);
    // 确认消息
    p_mm_2->ack("test_queue", p_msg1->payload().propeties().id());
    EXPECT_EQ(p_mm_2->total_count("test_queue"), 3);
    EXPECT_EQ(p_mm_2->waitcak_count("test_queue"), 0);
    EXPECT_EQ(p_mm_2->durable_count("test_queue"), 2);

    // 继续确认消息（测试垃圾回收）
    MessagePtr p_msg2 = p_mm_2->front("test_queue");
    ASSERT_NE(p_msg2, nullptr);
    EXPECT_EQ(p_msg2->payload().body(), std::string("Hello World-2"));
    p_mm_2->ack("test_queue", p_msg2->payload().propeties().id());
    debug_msg_info(p_msg2);

    // 此时符合gc条件，自动垃圾回收 (为了测试gc，将条件总消息数大于2000取消)
    ASSERT_EQ(p_mm_2->total_count("test_queue"), 1);
}

// 继“确认消息测试”后，测试垃圾回收后，未读取的消息是否符合预期
TEST(MessageTest, select_test_2)
{
    MessagePtr p_msg3 = p_mm_2->front("test_queue");
    ASSERT_NE(p_msg3, nullptr);
    debug_msg_info(p_msg3);
    EXPECT_EQ(p_msg3->payload().body(), std::string("Hello World-3"));
    EXPECT_EQ(p_mm_2->getable_count("test_queue"), 0);
    EXPECT_EQ(p_mm_2->waitcak_count("test_queue"), 1);

    // 确认消息
    p_mm_2->ack("test_queue", p_msg3->payload().propeties().id());
    EXPECT_EQ(p_mm_2->total_count("test_queue"), 0);
    EXPECT_EQ(p_mm_2->waitcak_count("test_queue"), 0);
    EXPECT_EQ(p_mm_2->durable_count("test_queue"), 0);
}

int main(int argc, char* argv[])
{
    testing::InitGoogleTest(&argc, argv);
    testing::AddGlobalTestEnvironment(new MessageTest);
    RUN_ALL_TESTS();

    return 0;
}

